const toString = Object.prototype.toString

/**
 * 检查值是否为指定类型
 * @param {*} val 要检查的值
 * @param {string} type 期望的类型名称（如'Object', 'Array'等）
 * @returns {boolean} 是否匹配类型
 */
export function is(val, type) {
    return toString.call(val) === `[object ${type}]`
}

/**
 * 检查值是否已定义
 * @param {*} val 要检查的值
 * @returns {boolean} 是否不为undefined
 */
export function isDef(val) {
    return typeof val !== 'undefined'
}

/**
 * 检查值是否未定义
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为undefined
 */
export function isUndef(val) {
    return typeof val === 'undefined'
}

/**
 * 检查值是否为null
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为null
 */
export function isNull(val) {
    return val === null
}

/**
 * 检查值是否为空字符串
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为空字符串
 */
export function isWhitespace(val) {
    return val === ''
}

/**
 * 检查值是否为对象（非null且基础对象）
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为对象
 */
export function isObject(val) {
    return !isNull(val) && is(val, 'Object')
}

/**
 * 检查值是否为数组
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为数组
 */
export function isArray(val) {
    return val && Array.isArray(val)
}

/**
 * 检查值是否为字符串
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为字符串类型
 */
export function isString(val) {
    return is(val, 'String')
}

/**
 * 检查值是否为数字
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为数字类型
 */
export function isNumber(val) {
    return is(val, 'Number')
}

/**
 * 检查值是否为布尔值
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为布尔类型
 */
export function isBoolean(val) {
    return is(val, 'Boolean')
}

/**
 * 检查值是否为日期对象
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为Date实例
 */
export function isDate(val) {
    return is(val, 'Date')
}

/**
 * 检查值是否为正则表达式
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为RegExp实例
 */
export function isRegExp(val) {
    return is(val, 'RegExp')
}

/**
 * 检查值是否为函数
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为函数类型
 */
export function isFunction(val) {
    return typeof val === 'function'
}

/**
 * 检查值是否为Promise对象
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为Promise且包含then/catch方法
 */
export function isPromise(val) {
    return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch)
}

/**
 * 检查值是否为DOM元素
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为带有tagName属性的对象
 */
export function isElement(val) {
    return isObject(val) && !!val.tagName
}

/**
 * 检查值是否为Window对象
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为Window实例
 */
export function isWindow(val) {
    return typeof window !== 'undefined' && isDef(window) && is(val, 'Window')
}

/**
 * 检查值是否为null或undefined
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为null或undefined
 */
export function isNullOrUndef(val) {
    return isNull(val) || isUndef(val)
}

/**
 * 检查值是否为null/undefined或空字符串
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为null/undefined/空字符串
 */
export function isNullOrWhitespace(val) {
    return isNullOrUndef(val) || isWhitespace(val)
}

/**
 * 检查值是否为空容器
 * 空数组、空字符串、空对象、空Map或空Set
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为空容器
 */
export function isEmpty(val) {
    if (isArray(val) || isString(val)) {
        return val.length === 0
    }

    if (val instanceof Map || val instanceof Set) {
        return val.size === 0
    }

    if (isObject(val)) {
        return Object.keys(val).length === 0
    }

    return false
}

/**
 * 类似mysql的IFNULL函数
 * @param {number | boolean | string} val 要检查的值
 * @param {number | boolean | string} [def=''] 备用值
 * @returns {number | boolean | string} val为null/undefined/空字符串时返回def，否则返回val
 */
export function ifNull(val, def = '') {
    return isNullOrWhitespace(val) ? def : val
}

/**
 * 检查是否为标准URL格式
 * @param {string} path 要检查的路径
 * @returns {boolean} 是否符合URL格式
 */
export function isUrl(path) {
    const reg = /^https?:\/\/[-\w+&@#/%?=~|!:,.;]+[-\w+&@#/%=~|]$/
    return reg.test(path)
}

/**
 * 检查是否为外部链接
 * @param {string} path 要检查的路径
 * @returns {boolean} 是否以http/https/mailto/tel开头
 */
export function isExternal(path) {
    return /^https?:|mailto:|tel:/.test(path)
}

/** 是否在服务端环境 */
export const isServer = typeof window === 'undefined'

/** 是否在客户端环境 */
export const isClient = !isServer

/**
 * 检查是否为原始对象（非数组/函数/宿主对象）
 * @param {*} val 需要检查的值
 * @returns {boolean} 是否为纯对象（{} 类型）
 */
export function isPlainObject(val) {
    return isObject(val) && Object.getPrototypeOf(val) === Object.prototype
}

/**
 * 检查是否为 NaN 值（避免全局 isNaN 的陷阱）
 * @param {*} val 需要检查的值
 * @returns {boolean} 是否为 NaN
 */
export function isNaN(val) {
    return Number.isNaN(val)
}

/**
 * 检查是否为 Symbol 类型
 * @param {*} val 需要检查的值
 * @returns {boolean} 是否为 Symbol
 */
export function isSymbol(val) {
    return is(val, 'Symbol')
}

/**
 * 检查是否为 Error 实例
 * @param {*} val 需要检查的值
 * @returns {boolean} 是否为 Error 对象
 */
export function isError(val) {
    return is(val, 'Error')
}

/**
 * 验证是否为有效邮箱地址
 * @param {string} email 需要验证的邮箱
 * @returns {boolean} 是否符合邮箱格式
 */
export function isEmail(email) {
    const reg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
    return isString(email) && reg.test(email)
}

/**
 * 检查是否为数字类型（包含可转换的字符串）
 * @param {*} val 需要检查的值
 * @returns {boolean} 是否为有效数字
 */
export function isNumeric(val) {
    return !isNaN(val) && (!isArray(val) && !isBoolean(val))
}

/**
 * 检查是否为十六进制颜色码
 * @param {string} color 需要验证的颜色值
 * @returns {boolean} 是否为 #RRGGBB 格式
 */
export function isHexColor(color) {
    const reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/
    return isString(color) && reg.test(color)
}

/**
 * 检查值是否为Blob对象
 * @param {*} val 要检查的值
 * @returns {boolean} 是否为Blob实例
 */
export function isBlob(val) {
    return typeof Blob !== 'undefined' && val instanceof Blob;
}


export const isExternalUrl = (url) => /^(https?:|mailto:|tel:)/.test(url);